﻿using System;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using InstantSpine.Core.Properties;
using System.Runtime.Serialization;
using InstantSpine.Core.MaterialModels;

namespace InstantSpine.Core
{
    /// <summary>
    /// materials describing the individual tissues of the spine
    /// </summary>
    /// <remarks>
    /// ONLY considers material really used in ansys2abaqus.mac AND configureable via material
    /// paramters in init-default-abaqus-mat-params.mac;
    /// does NOT (yet) consider ALL materials defined in abaqus-materialDefinitions.mac!
    /// </remarks>
    [DataContract]
    public sealed class SpineMaterials
    {
        ObservableCollection<MaterialViewModel> allMaterials;

        [XmlIgnore]
        public ObservableCollection<MaterialViewModel> AllMaterials {
            get {
                if (allMaterials == null) {
                    allMaterials = new ObservableCollection<MaterialViewModel> { 
                        Cortex, 
                        Spongiosa, 
                        FacetsInnerLayer,                          
                        CartilaginousEndplate,
                        OuterCartilaginousEndplate,                    
                        AnnulusGroundSubstanceAnterior,
                        AnnulusGroundSubstance,
                        AnnulusGroundSubstancePosterior,
                        Nucleus,
                        FollowerLoadAnchor,
                        FiberLayers,
                        SSL,
                        ALL,
                        PLL,
                        LF,
                        ISL,
                        ITL,
                        CL
                    };
                }

                return allMaterials; 
            }
        }

        /// <summary>
        /// material of inner facet joint elements
        /// </summary>
        /// <remarks>ParaSpine parameters: mpFacetsEmod, mpFacetsNu; Abaqus material: CARTILAGE_FACETS</remarks>
        [DataMember]
        public IsoLinearElasticMaterial FacetsInnerLayer { get; private set; }

        /// <summary>
        /// cortex material (vertebral bodies and posterior elements)
        /// </summary>
        /// <remarks>ParaSpine parameters: mpCortexEmod, mpCortexNu; Abaqus material: CORTEX</remarks>                
        [DataMember]
        public IsoLinearElasticMaterial Cortex { get; private set; }

        /// <summary>
        /// material assigned to spongy bone inside vertebral bodies
        /// </summary>
        /// <remarks>ParaSpine parameters: mpSpongiosaEmod, mpSpongiosaNu; Abaqus material: SPONGIOSA</remarks>        
        [DataMember]
        public IsoLinearElasticMaterial Spongiosa { get; private set; }

        /// <summary>
        /// cartilginous material of endplates (above nucleus)
        /// </summary>
        /// <remarks>ParaSpine parameters: mpCartEPEmod, mpCartEPNu; Abaqus material: CARTILAGE_EP</remarks>
        [DataMember]
        public IsoLinearElasticMaterial CartilaginousEndplate { get; private set; }

        /// <summary>
        /// cartilginous material of endplates (above annulus)
        /// </summary>
        /// <remarks>ParaSpine parameters: mpCartEPAnnEmod, mpCartEPAnnNu; Abaqus material: CARTILAGE_ANN</remarks>        
        [DataMember]
        public IsoLinearElasticMaterial OuterCartilaginousEndplate { get; private set; }

        /// <summary>
        /// material assigned to elements in close proximity to the node
        /// where the follower load is applied (to avoid excessive mesh distortion);
        /// set to spongiosa material, if now follower load is active
        /// </summary>
        /// <remarks>ParaSpine parameters: mpFollowerAnchorEMod, mpFollowerAnchorNu; Abaqus material: FOLLOW_ANCHOR</remarks>
        [DataMember]
        public IsoLinearElasticMaterial FollowerLoadAnchor { get; private set; }

        /// <summary>
        /// ground substance of the medial annulus
        /// </summary>
        /// <remarks>ParaSpine parameters: mpAnnulusMedEmod, mpAnnulusMedNu; Abaqus material: ANNULUS</remarks>
        [DataMember]
        public NeoHookeanMaterial AnnulusGroundSubstance { get; private set; }

        /// <summary>
        /// ground substance of the anterior annulus
        /// </summary>
        /// <remarks>ParaSpine parameters: mpAnnulusAntEmod, mpAnnulusAntNu; Abaqus material: ANNULUS_ANT</remarks>
        [DataMember]
        public NeoHookeanMaterial AnnulusGroundSubstanceAnterior { get; private set; }

        /// <summary>
        /// ground substance of the posterior annulus
        /// </summary>
        /// <remarks>ParaSpine parameters: mpAnnulusPostEmod, mpAnnulusPostNu; Abaqus material: ANNULUS_POST</remarks>
        [DataMember]
        public NeoHookeanMaterial AnnulusGroundSubstancePosterior { get; private set; }

        /// <summary>
        /// fluid properties of the nucleus
        /// </summary>
        /// <remarks>ParaSpine parameters: mpNucleusBulk (density: 1.0); Abaqus: *FLUID DENSITY/BULK MODULUS</remarks>        
        [DataMember]
        public HydraulicFluidMaterial Nucleus { get; private set; }
        
        /// <summary>
        /// material of the seven layers of simulated annulus fibers
        /// </summary>
        /// <remarks>ParaSpine parameters: mpAnnulusFiberLayerX (with X in 1..8, each of which is an 
        /// array of 27 stress-strain pairs); Abaqus materials: FIBER_n</remarks>
        [DataMember]
        public LayeredAnnulusFibers FiberLayers { get; private set; }

        /// <summary>
        /// Material of the supraspinous ligament
        /// </summary>
        /// <remarks>ParaSpine paramters: mpSSL (n x 2 array of stress-strain pairs); Abaqus material: SSL</remarks>
        [DataMember]
        public MarlowUniaxialMaterial SSL { get; private set; }

        /// <summary>
        /// Material of the anterior longitudinal ligament
        /// </summary>
        /// <remarks>ParaSpine paramters: mpALL34 (n x 2 array of stress-strain pairs); Abaqus material: ALL_34</remarks>
        [DataMember]
        public MarlowUniaxialMaterial ALL { get; private set; }

        /// <summary>
        /// Material of the posterior longitudinal ligament
        /// </summary>
        /// <remarks>ParaSpine paramters: mpPLL (n x 2 array of stress-strain pairs); Abaqus material: PLL</remarks>
        [DataMember]
        public MarlowUniaxialMaterial PLL { get; private set; }

        /// <summary>
        /// Material of the ligamenta flava
        /// </summary>        
        /// <remarks>ParaSpine paramters: mpLF (n x 2 array of stress-strain pairs); Abaqus material: LF</remarks>
        [DataMember]
        public MarlowUniaxialMaterial LF { get; private set; }

        /// <summary>
        /// Material of the intraspinous ligament
        /// </summary>
        /// <remarks>ParaSpine paramters: mpISL (n x 2 array of stress-strain pairs); Abaqus material: ISL</remarks>
        [DataMember]
        public MarlowUniaxialMaterial ISL { get; private set; }

        /// <summary>
        /// Material of the intertransverse ligament
        /// </summary>
        /// <remarks>ParaSpine paramters: mpITL (n x 2 array of stress-strain pairs); Abaqus material: ITL</remarks>
        [DataMember]
        public MarlowUniaxialMaterial ITL { get; private set; }

        /// <summary>
        /// Non-linear elastic behavior of the capsular ligaments
        /// </summary>
        /// <remarks>ParaSpine paramters: mpCL (n x 2 array of force-deflection pairs); 
        /// Applied to A_CL_SPRINGS Abaqus element set (no explicit name)</remarks>
        [DataMember]
        public NonlinearSpringBehavior CL { get; private set; }

        public SpineMaterials(IsoLinearElasticMaterial facets,
                              IsoLinearElasticMaterial cortex,
                              IsoLinearElasticMaterial spongiosa,
                              IsoLinearElasticMaterial cartilageEPNucleus,
                              IsoLinearElasticMaterial cartilageEPAnnulus,
                              NeoHookeanMaterial annulusGroundSubstance,
                              NeoHookeanMaterial annulusGroundSubstanceAnt,
                              NeoHookeanMaterial annulusGroundSubstancePost,
                              HydraulicFluidMaterial nucleus,
                              LayeredAnnulusFibers fibers,
                              MarlowUniaxialMaterial ssl,
                              MarlowUniaxialMaterial all,
                              MarlowUniaxialMaterial pll,
                              MarlowUniaxialMaterial lf,
                              MarlowUniaxialMaterial isl,
                              MarlowUniaxialMaterial itl,
                              NonlinearSpringBehavior cl,
                              IsoLinearElasticMaterial followerLoadAnchor = null) {
            
            this.AnnulusGroundSubstance = annulusGroundSubstance;
            this.AnnulusGroundSubstanceAnterior = annulusGroundSubstanceAnt;
            this.AnnulusGroundSubstancePosterior = annulusGroundSubstancePost;
            this.CartilaginousEndplate = cartilageEPNucleus;
            this.OuterCartilaginousEndplate = cartilageEPAnnulus;
            this.Cortex = cortex;
            this.FacetsInnerLayer = facets;
            this.Nucleus = nucleus;
            this.FiberLayers = fibers;
            this.Spongiosa = spongiosa;
            // if follower load anchor material not specified => use spongiosa material
            // (i.e. reference the SAME object)
            this.FollowerLoadAnchor = followerLoadAnchor ?? spongiosa;
            
            this.SSL = ssl;
            this.ALL = all;
            this.PLL = pll;
            this.LF = lf;
            this.ISL = isl;
            this.ITL = itl;
            this.CL = cl;
        }

        // TODO: re-use existing parameterized ctor to avoid code duplication
        public SpineMaterials() {
            // simple materials
            this.FacetsInnerLayer = new IsoLinearElasticMaterial(Resources.MaterialNameFacetJoints);
            this.Cortex = new IsoLinearElasticMaterial(Resources.MaterialNameCorticalShell);
            this.Spongiosa = new IsoLinearElasticMaterial(Resources.MaterialNameSpongiosa);
            this.CartilaginousEndplate = new IsoLinearElasticMaterial(Resources.MaterialNameCartEndplate);
            this.OuterCartilaginousEndplate = new IsoLinearElasticMaterial(Resources.MaterialNameCartEndplateOuter);
            this.AnnulusGroundSubstance = new NeoHookeanMaterial(Resources.MaterialNameAnnulusGroundSubstance);
            this.AnnulusGroundSubstanceAnterior = new NeoHookeanMaterial(Resources.MaterialNameAnnulusGroundSubstanceAnterior);
            this.AnnulusGroundSubstancePosterior = new NeoHookeanMaterial(Resources.MaterialNameAnnulusGroundSubstancePosterior);
            this.Nucleus = new HydraulicFluidMaterial(Resources.MaterialNameNucleus);
            this.FollowerLoadAnchor = new IsoLinearElasticMaterial(Resources.MaterialNameFollowerLoadAnchor);
            
            // complex materials (tabular data)
            this.FiberLayers = new LayeredAnnulusFibers(Resources.MaterialNameAnnulusFibers);
            this.SSL = new MarlowUniaxialMaterial(Resources.MaterialNameSSL);
            this.ALL = new MarlowUniaxialMaterial(Resources.MaterialNameALL);
            this.PLL = new MarlowUniaxialMaterial(Resources.MaterialNamePLL);
            this.LF = new MarlowUniaxialMaterial(Resources.MaterialNameLF);
            this.ISL = new MarlowUniaxialMaterial(Resources.MaterialNameISL);
            this.ITL = new MarlowUniaxialMaterial(Resources.MaterialNameITL);
            this.CL = new NonlinearSpringBehavior(Resources.MaterialNameCL);

            /*this.allMaterials = new Lazy<ObservableCollection<MaterialViewModel>>(() =>
                new ObservableCollection<MaterialViewModel> { 
                    Cortex, 
                    Spongiosa, 
                    FacetsInnerLayer,                          
                    CartilaginousEndplate,
                    OuterCartilaginousEndplate,                    
                    AnnulusGroundSubstanceAnterior,
                    AnnulusGroundSubstance,
                    AnnulusGroundSubstancePosterior,
                    Nucleus,
                    FollowerLoadAnchor,
                    FiberLayers,
                    SSL,
                    ALL,
                    PLL,
                    LF,
                    ISL,
                    ITL,
                    CL
                });*/
        }
    }
}